using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Grpc.Core;
using GrpcDemo.Protos;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using DemoClient = GrpcDemo.Protos.Demo.DemoClient;

namespace GrpcService1.Services;

public class DemoService : Demo.DemoBase
{
	private readonly IHttpContextAccessor _httpContextAccessor;
	private readonly DemoClient _demoClient;

	public DemoService(DemoClient demoClient, IHttpContextAccessor httpContextAccessor)
	{
		_demoClient = demoClient;
		_httpContextAccessor = httpContextAccessor;
	}

	[AllowAnonymous]
	public override Task<LoginReply> Login(LoginRequest request, ServerCallContext context)
	{
		if (!GlobalConst.GuestRoleUsername.Equals(request.UserName)
		    && !GlobalConst.AdminRoleUsername.Equals(request.UserName)
		    || !GlobalConst.Password.Equals(request.Password))
		{
			throw new RpcException(new Status(StatusCode.Unauthenticated, "用户名或密码错误"));
		}

		return Task.FromResult(new LoginReply
		{
			Token = GenToken(request)
		});
	}

	[Authorize]
	public override Task<ProfileReply> Profile(Empty request, ServerCallContext context)
	{
		var claims = _httpContextAccessor.HttpContext!.User.Claims.ToList();
		var id = claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)!.Value;
		var name = claims.FirstOrDefault(x => x.Type == ClaimTypes.Name)!.Value;
		var role = claims.FirstOrDefault(x => x.Type == ClaimTypes.Role)?.Value ?? ""; //角色可能为空，不要赋值null
		return Task.FromResult(new ProfileReply
		{
			Name = name,
			Id = int.Parse(id),
			Role = role
		});
	}

	[Authorize]
	public override Task<RandomReply> Random(RandomRequest request, ServerCallContext context)
	{
		var headers = context.RequestHeaders;
		var company = headers.GetValue("x-company");
		if (string.IsNullOrEmpty(company))
		{
			throw new RpcException(new Status(StatusCode.Unauthenticated, "x-company header is required"));
		}

		if (!"bsi".Equals(company))
		{
			throw new RpcException(new Status(StatusCode.InvalidArgument, "x-company header is InvalidArgument"));
		}

		var rand = System.Random.Shared.NextInt64(request.Limit);
		return Task.FromResult(new RandomReply
		{
			Number = rand
		});
	}

	[Authorize(Roles = GlobalConst.AdminRoleValue)]
	public override async Task<ManageReply> Manage(Empty request, ServerCallContext context)
	{
		//admin角色访问
		//1.透传token, grpc客户端远程调用Random接口
		//2.返回结果为Random接口返回的随机数
		//3.ResponseHeader里面写入x-company
		var headers = context.RequestHeaders;
		var resp = await _demoClient.RandomAsync(new RandomRequest { Limit = 1000 }, headers);

		await context.WriteResponseHeadersAsync(headers);
		return new ManageReply
		{
			Number = resp.Number
		};
	}

	private static readonly JwtSecurityTokenHandler JwtTokenHandler = new();

	private static string GenToken(LoginRequest request)
	{
		var claims = new List<Claim>();
		//guest没有角色信息
		if (GlobalConst.GuestRoleUsername.Equals(request.UserName))
		{
			claims.Add(new Claim(ClaimTypes.NameIdentifier, 1.ToString()));
			//claims.Add(new Claim(ClaimTypes.Role, GlobalConst.GuestRoleUsername));
		}

		//bsi 有角色admin的角色
		if (GlobalConst.AdminRoleUsername.Equals(request.UserName))
		{
			claims.Add(new Claim(ClaimTypes.NameIdentifier, 2.ToString()));
			claims.Add(new Claim(ClaimTypes.Role, GlobalConst.AdminRoleValue));
		}

		claims.Add(new Claim(ClaimTypes.Name, request.UserName));
		var credentials = new SigningCredentials(GlobalConst.RsaPrivateSecurityKey, SecurityAlgorithms.RsaSha256);
		var token = new JwtSecurityToken("ExampleServer", "ExampleClients", claims,
			expires: DateTime.Now.AddDays(60),
			signingCredentials: credentials);
		return JwtTokenHandler.WriteToken(token);
	}
}
